package com.rw.tool.util.string;

import com.rw.tool.util.escape.EscapeElement;
import com.rw.tool.util.escape.EscapeParseException;
import com.rw.tool.util.escape.EscapeUtil;

import java.util.List;

/**
 * 字符串格式化工具
 */
public class StringFormatter {
    private static final String FORMAT_TARGET = "{}";

    private static final String UNKNOWN_ESCAPE = "There is a unknown escape : '{}'";

    /**
     * 类似于slf4j的字符串格式化
     */
    public static String format(String input, Object... args) {
        List<EscapeElement> elementList = EscapeUtil.parse(input, '\\');

        // 遍历转义链，插入元素
        ArgsReplace argsReplace = new ArgsReplace(args, FORMAT_TARGET);
        StringBuilder result = new StringBuilder();
        for (EscapeElement element : elementList) {
            // 如果是普通内容，则直接替换
            if (element.isContent()) {
                String content = element.getContent();
                String replaced = StringSearcher.replaceAll(content, FORMAT_TARGET, argsReplace);
                result.append(replaced);
            } else {
                // 如果是转义内容，则直接转义
                escape(result, element);
            }
        }

        return result.toString();
    }

    /**
     * 从字符串中替换所有目标子串
     *
     * @param input     输入字符串
     * @param replaceTo 替换为
     * @return 替换后的字符串
     */
    public static String replaceAll(String input, String replaceTo) {
        // 获取转义链
        List<EscapeElement> elementList = EscapeUtil.parse(input, '\\');
        StringBuilder result = new StringBuilder();
        for (EscapeElement element : elementList) {
            if (element.isContent()) {
                // 如果是普通内容
                String str = element.getContent().replaceAll("\\{}", replaceTo);
                result.append(str);
            } else {
                // 如果是转义内容，则直接转义
                escape(result, element);
            }
        }
        return result.toString();
    }

    private static void escape(StringBuilder result, EscapeElement element) {
        switch (element.getContent()) {
            case "\\{":
                result.append("{");
                break;
            case "\\\\":
                result.append("\\");
                break;
            default:
                throw new EscapeParseException(format(UNKNOWN_ESCAPE, element.getContent()));
        }
    }

    /**
     * 参数替换器，依次返回args
     */
    private static class ArgsReplace implements StringSearcher.Replace {
        private final Object[] args;

        private final String defaultStr;

        private int index;

        public ArgsReplace(Object[] args, String defaultStr) {
            this.args = args;
            this.defaultStr = defaultStr;
        }


        @Override
        public String replace(int count) {
            if (index >= args.length) {
                return defaultStr;
            }

            Object arg = args[index];
            index++;
            return arg.toString();
        }
    }
}
